[進階 js 11] this


Posted by tzutzu858 on 2021-03-30

在沒有意義的地方呼叫 this,預設值會是什麼?

this 的值取決於在什麼環境,依據環境不同,this 值也會不同
在 node.js 的 this 預設值會是 global
在瀏覽器上跑的話,this 會是 Window
但在嚴格模式,也就是設定 use strictthis 的預設值會是 undefined

'use strict'; // 開啟嚴格模式

function test() {
  console.log(this); // undefined
}
test();

DOM 元素中的 this

這邊的 this 就會是你實際做操作的東西,比如說用 click ,那 this 就是你點到哪個按鈕就是哪個按鈕

document.querySelector('.btn').addEventListener('click', function() {
  console.log(this)   
})

另外兩種呼叫 function 的方法:call 與 apply

前一篇文章有提到在模擬 new 背後在做的事情,有用到 call 這個 function
第一個參數傳的是什麼,this 就是什麼

'use strict';
function test() {
  console.log(this);
}
test.call(123);     // 123
test.call({});      // {}
test.call([1]);     // [ 1 ]

除了 .call() 還有 .apply()
.call() 一樣第一個參數就是 this 的值

那和 .call() 差異在哪 ?

差異在於 .apply() 第二個參數會是 array

function test(a, b, c) {
  console.log(this)
  console.log(a, b, c)
}

test.call(123, 1, 2, 3)
test.apply(123, [1, 2, 3])


  • this 只有在跟物件導向扯上關係的時候,this 才有意義,在這關係以外基本上沒什麼意義
  • this 在程式碼的哪邊無關,跟怎麼被呼叫有關
const obj = {
  a: 123,
  test: function(){
    console.log(this)
  }
}

obj.test()

上面程式碼的 this 是 obj 本身

const obj = {
  a: 123,
  test: function(){
    console.log(this)
  }
}

var func = obj.test
func()  // obj.test()

上面程式碼的 this 的值變成 undefined
不是同一個 function 嗎? 怎麼值就不一樣了
所以這就是前面提到的 this 在程式碼的哪邊無關,跟怎麼被呼叫有關


上述例子可以用不同角度來看會比較好理解
首先 obj.test() 可以看成 obj.test.call(obj)
假設裡面還有一層 inner

const obj = {
  a: 123,
  inner: {
      test: function(){
          console.log(this)
      }
  }
}

obj.inner.test() // 可以看成 obj.inner.test.call(obj.inner)
// 上面這樣執行, this 都是 inner 這個物件

const func = obj.inner.test
func() 
// 上面這樣執行, this 就會是 undefined
// 所以 func() 可以看成 func.call(undefined)

因為 func() 前面沒有其他東西,在 .call 可以看成傳 undefined 進去
而前面 obj.inner.test() ,test 前面還有 obj.inner. 所以在 .call 就是傳前面東西進去 obj.inner.test.call(obj.inner)


做個小測驗來了解對 this 熟不熟

'use strict';

function log() {
  console.log(this);
}

var a = { a: 1, log: log };
var b = { a: 2, log: log };

log();
a.log();

b.log.apply(a)

答案

'use strict';

function log() {
  console.log(this);
}

var a = { a: 1, log: log };
var b = { a: 2, log: log };

log(); // undefined
a.log(); // {a: 1, log: [Function: log] }

b.log.apply(a) // {a: 1, log: [Function: log] }

綁定 this 的值,用 .bind()

.bind() 會直接回傳一個 function
.call().apply() 會直接呼叫 function
.bind() 後即便再加 .call().apply() 都無法去改變 this 的值

const obj = {
  a: 1,
  test: function() {
     console.log(this)
  }
}

const bindTest = obj.test.bind('abc')
bindTest() // this 值是 abc
bindTest.call(123) // this 值還是 abc

arrow function 的 this

class Test{
  run() {
    console.log('run this:', this) // run this: Test {}
    setTimeout(function() {
      console.log(this) // 瀏覽器是 Window,嚴格模式下是 undefined
    }, 100)
  }
}

const t = new Test()
t.run()

但對於箭頭函式事情就變得不一樣

class Test{
  run() {
    console.log('run this:', this) // run this: Test {}
    setTimeout(() => {
      console.log(this) // Test {}
    }, 100)
  }
}

const t = new Test()
t.run()

箭頭函式裡面的 this 跟怎麼呼叫沒有關係,跟定義在程式碼哪裡比較有關係,這點比較像 Scope(作用域)的機制


參考文章
淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
關於this綁定的四種方式










Related Posts

The introduction and difference between class component and function component in React

The introduction and difference between class component and function component in React

Spring boot系列(四)Controller

Spring boot系列(四)Controller

使用 Javascript 取得元素的座標

使用 Javascript 取得元素的座標


Comments